import { Camera, Vector2, Vector3, Raycaster, Ray, Sphere, MOUSE, Quaternion, MathUtils, PerspectiveCamera, Plane } from 'three';
import Config from '../Config';
import GlobalScene from '../render/GlobalScene';
import MapController from './MapController';

export default class MouseController { // extends MapControls
    private camera: PerspectiveCamera;
    private domElement: HTMLElement;

    private initIntersectPoint: Vector3;
    private tempCamera: PerspectiveCamera;
    private sightPoint: Vector3;
    private scrollSpeed: number = 0.05;
    private minDistanceToGround = 50; //机视线距离地面的最小距离
    private plane;//垂直于相机的平面
    private isRightOperator: boolean = false; //是否右键操作鼠标
    private isOpenPcik: boolean = true; //是否开启鼠标拾取
    private mapController: MapController;
    private lastMapLevel: number;

    public constructor(camera: PerspectiveCamera, domElement: HTMLElement, mapController: MapController) {
        this.camera = camera;
        this.domElement = domElement;
        this.mapController = mapController;

        this.initMouseEvent();
    }

    private initMouseEvent() {
        let self = this;
        //箭头鼠标左键点击
        this.domElement.addEventListener('mousedown', (event) => {
            if (event.button === MOUSE.MIDDLE) return;

            self.tempCamera = self.camera.clone();

            self.sightPoint = self.getSightPoint(self.tempCamera);

            let planeNormal;
            if (event.button === MOUSE.RIGHT) {
                self.isRightOperator = true;
                planeNormal = self.tempCamera.position.clone().normalize().multiplyScalar(1);
            } else {
                self.isRightOperator = false;
                planeNormal = self.tempCamera.position.clone().normalize().multiplyScalar(-1);
            }

            let planeConstant = self.sightPoint.length(); //6378137; // 1000; //
            self.plane = new Plane(planeNormal, planeConstant);

            self.initIntersectPoint = self.getIntersectPoint(event, self.tempCamera, 'down');
        });
        this.domElement.addEventListener('mouseup', (event) => {
            self.freeMouse();
        });

        this.domElement.addEventListener('mousemove', (event) => {
            if (self.initIntersectPoint == null) return;

            let currentIntersectPoint = self.getIntersectPoint(event, self.tempCamera, 'move');
            if (currentIntersectPoint == null) return;

            let ellipsoidCenter = Config.EllipsoidConfig.center;

            let rotateCenter = ellipsoidCenter;
            if (self.isRightOperator) { //右键操作
                rotateCenter = self.sightPoint;
            }
            // 计算旋转轴（初始点与当前点的法向量叉积）
            let initVector = self.initIntersectPoint.clone().sub(rotateCenter).normalize();
            let currentVector = currentIntersectPoint.clone().sub(rotateCenter).normalize();
            const rotationAxis = new Vector3().crossVectors(initVector, currentVector).normalize();
            if (rotationAxis.length() <= 0.001) { //initVector向量和currentVector向量平行
                return;
            }

            let currentCameraPoint;
            if (self.isRightOperator) { //右键操作
                // 计算旋转角度（两点与球心连线的夹角）
                const rotationAngle = 2 * Math.PI + (initVector.angleTo(currentVector));
                // 应用旋转：相机绕球心旋转
                const quaternion = new Quaternion().setFromAxisAngle(rotationAxis, rotationAngle);

                let sightVector = self.tempCamera.position.clone().sub(self.sightPoint);
                sightVector = sightVector.applyQuaternion(quaternion);
                currentCameraPoint = self.sightPoint.clone().add(sightVector);
            } else { //左键操作
                // 计算旋转角度（两点与球心连线的夹角）
                const rotationAngle = 2 * Math.PI - (initVector.angleTo(currentVector));
                // 应用旋转：相机绕球心旋转
                const quaternion = new Quaternion().setFromAxisAngle(rotationAxis, rotationAngle);

                currentCameraPoint = self.tempCamera.position.clone().sub(ellipsoidCenter).applyQuaternion(quaternion);
            }

            self.camera.position.copy(currentCameraPoint);
            GlobalScene.instance.updateCameraNear();
            self.camera.lookAt(ellipsoidCenter); // 确保相机始终朝向球心

            let sightPoint = self.getSightPoint(self.camera);
            let curMapLevel = self.mapController.computeLevel(sightPoint);
            let visibleTileStrSet = self.mapController.computeVisibleTiles(sightPoint, curMapLevel);
            self.mapController.loadTiles(visibleTileStrSet);
            self.lastMapLevel = curMapLevel;
        });
        
        this.domElement.addEventListener('mousewheel', (event) => {
            let ellipsoidCenter = Config.EllipsoidConfig.center;
            self.tempCamera = self.camera.clone();

            this.sightPoint = self.getSightPoint(self.tempCamera);
            let sightDirection = self.tempCamera.position.clone().sub(this.sightPoint);

            const scrollFactor = event.deltaY > 0 ? (1 + self.scrollSpeed) : (1 - self.scrollSpeed);
            let currentCameraPoint = this.sightPoint.clone().add(sightDirection.multiplyScalar(scrollFactor));

            self.tempCamera.position.copy(currentCameraPoint);

            let distanceSightToCenter = this.sightPoint.clone().sub(ellipsoidCenter).length();
            let distanceCameraToCenter = currentCameraPoint.sub(ellipsoidCenter).length();
            if ((event.deltaY < 0) && (distanceCameraToCenter - distanceSightToCenter <= self.minDistanceToGround)) {//因为相机视线距离地面的距离太近，相机几乎都快贴地了，如果在拉近相机会钻到地面之下，因此return掉。
                return;
            }

            self.camera.position.copy(self.tempCamera.position);
            GlobalScene.instance.updateCameraNear();
            self.camera.lookAt(ellipsoidCenter); // 确保相机始终朝向球心

            let sightPoint = self.getSightPoint(self.camera);
            let curMapLevel = self.mapController.computeLevel(sightPoint);
            let visibleTileStrSet = self.mapController.computeVisibleTiles(sightPoint, curMapLevel);
             console.log('lastMapLevel:' + self.lastMapLevel);
            if (self.lastMapLevel == undefined || (self.lastMapLevel == curMapLevel)) {
                self.mapController.loadTiles(visibleTileStrSet);
            } else {
                let zoomType = (event.deltaY < 0) ? 'down' : 'up';
                self.mapController.loadZoomTiles(visibleTileStrSet, zoomType as 'down' | 'up', curMapLevel);
            }
            console.log('---------------');
            self.lastMapLevel = curMapLevel;
            self.freeMouse();
        });

        // 禁用右键菜单
        this.domElement.addEventListener('contextmenu', function (e) {
            e.preventDefault();
            return false;
        });
    }

    // private computeLevel() {
    //     let sightPoint = this.getSightPoint(this.camera);
    //     let distanceCameraToSight = this.camera.position.distanceTo(sightPoint);
    //     let ellipsoidCenter = Config.EllipsoidConfig.center;
    //     let currentRadius = sightPoint.clone().distanceTo(ellipsoidCenter);
    //     let mapLevel = Math.log2(currentRadius / distanceCameraToSight);
    //     console.log('mapLevel: ' + mapLevel + ', ' + distanceCameraToSight);

    //     return mapLevel;
    // }

    private freeMouse() {
        this.initIntersectPoint = null;
        this.tempCamera = null;
        this.sightPoint = null;
        this.plane = null;
        this.isRightOperator = false;
    }

    private getIntersectPoint(event, camera, operatorType) { //和地球椭球做射线相交
        let farNdcPoint = new Vector3();

        // 将鼠标位置归一化到[-1,1]
        farNdcPoint.x = (event.clientX / window.innerWidth) * 2 - 1;
        farNdcPoint.y = -(event.clientY / window.innerHeight) * 2 + 1;
        farNdcPoint.z = 1;

        let nearNdcPoint = farNdcPoint.clone();
        nearNdcPoint.z = -1;

        let farWorldPoint = farNdcPoint.clone().unproject(camera);
        let nearWorldPoint = nearNdcPoint.clone().unproject(camera);
        let direction = farWorldPoint.clone().sub(nearWorldPoint.clone()).normalize();

        let ray: Ray = new Ray(nearWorldPoint.clone(), direction.clone());
        if (operatorType == 'down' && this.isOpenPcik) {
            let intersectResult = Config.Ellipsoid.intersectRay(ray);

            if (intersectResult) {
                let projectedPoint = Config.Ellipsoid.scaleToGeodeticSurface(intersectResult[0]);
                let pickedLnglat = Config.Ellipsoid.toGeography(projectedPoint);
                console.log('pickedLnglat:', pickedLnglat, projectedPoint);
            }
        }
        //求出ray和plane的相交点
        let intersectPoint = new Vector3();
        intersectPoint = ray.intersectPlane(this.plane, intersectPoint);
        return intersectPoint;
    }

    public getSightPoint(camera) { //得到相机视线看向地球上的位置
        let cameraPosition = camera.position.clone();
        let sightDirection = Config.EllipsoidConfig.center.clone().sub(cameraPosition).normalize();

        let ray: Ray = new Ray(cameraPosition, sightDirection);
        let intersectResult = Config.Ellipsoid.intersectRay(ray);
        if (intersectResult) {
            // let projectedPoint = Config.Ellipsoid.scaleToGeodeticSurface(intersectResult[0]);
            return intersectResult[0];
        }
        return null;
    }

    public loadTiles() {
        let sightPoint = this.getSightPoint(this.camera);
        let mapLevel = this.mapController.computeLevel(sightPoint);
        let visibleTileStrSet = this.mapController.computeVisibleTiles(sightPoint, mapLevel);
        this.mapController.loadTiles(visibleTileStrSet);
    }
}

